初次尝试NestJS中的微服务(TCP方式)
NestJS原生支持微服务架构,提供了多种传输层实现。本节通过TCP方式创建第一个NestJS微服务,包含服务端和客户端的完整搭建流程。
微服务架构概览
客户端浏览器
↓ HTTP请求
客户端应用(端口3010)──TCP通信──→ 微服务端(端口3000)
↑ ↑
HTTP响应 处理业务逻辑
text
搭建微服务端
1. 创建项目
# 创建微服务端项目
mkdir microservices-demo
cd microservices-demo
nest new app # 选择pnpm作为包管理器
cd app
# 安装微服务依赖
pnpm install @nestjs/microservices
bash
2. 修改main.ts
将默认的HTTP应用改为微服务应用:
// src/main.ts
import { NestFactory } from '@nestjs/core';
import { MicroserviceOptions, Transport } from '@nestjs/microservices';
import { AppModule } from './app.module';
async function bootstrap() {
const app = await NestFactory.createMicroservice<MicroserviceOptions>(
AppModule,
{
transport: Transport.TCP,
options: {
host: 'localhost',
port: 3000,
},
},
);
await app.listen();
}
bootstrap();
typescript
关键变化:
createMicroservice替代create- 配置
transport: Transport.TCP指定TCP传输层 options中设置监听端口
3. 创建消息处理器
在Controller中使用@MessagePattern装饰器定义消息处理逻辑:
// src/app.controller.ts
import { Controller } from '@nestjs/common';
import { MessagePattern, Payload } from '@nestjs/microservices';
@Controller()
export class AppController {
@MessagePattern({ cmd: 'sum' })
accumulate(@Payload() data: number[]): number {
return data.reduce((acc, val) => acc + val, 0);
}
}
typescript
@MessagePattern:定义消息的模式(pattern),客户端发送消息时必须匹配这个模式。{ cmd: 'sum' } 是一个唯一标识符。
@Payload:提取消息中的数据负载。
启动后终端会显示:Nest microservice successfully started
搭建客户端
1. 创建客户端项目
cd ..
nest new app-client
cd app-client
pnpm install @nestjs/microservices
bash
2. 注册微服务客户端
在AppModule中注册ClientsModule:
// src/app.module.ts
import { Module } from '@nestjs/common';
import { ClientsModule, Transport } from '@nestjs/microservices';
import { AppController } from './app.controller';
import { AppService } from './app.service';
@Module({
imports: [
ClientsModule.register([
{
name: 'MATH_SERVICE', // 注入令牌(Injection Token)
transport: Transport.TCP,
options: {
host: 'localhost',
port: 3000, // 微服务端的端口
},
},
]),
],
controllers: [AppController],
providers: [AppService],
})
export class AppModule {}
typescript
name属性:作为依赖注入的令牌(Injection Token),后续通过@Inject()注入使用。
3. 在Controller中调用微服务
// src/app.controller.ts
import { Controller, Get, Inject } from '@nestjs/common';
import { ClientProxy } from '@nestjs/microservices';
import { AppService } from './app.service';
@Controller()
export class AppController {
constructor(
private readonly appService: AppService,
@Inject('MATH_SERVICE') private readonly client: ClientProxy,
) {}
@Get()
getHello() {
// 向微服务发送消息
return this.client.send({ cmd: 'sum' }, [1, 2, 3]);
}
}
typescript
4. 修改客户端端口
// src/main.ts
import { NestFactory } from '@nestjs/core';
import { AppModule } from './app.module';
async function bootstrap() {
const app = await NestFactory.create(AppModule);
await app.listen(3010); // 客户端使用不同端口
}
bootstrap();
typescript
测试验证
# 启动微服务端(端口3000)
cd app && pnpm start:dev
# 启动客户端(端口3010)
cd app-client && pnpm start:dev
# 访问客户端
curl http://localhost:3010
# 响应:6(1+2+3的结果)
bash
ClientProxy的懒加载机制
ClientProxy默认采用懒加载策略:
- 不会立即建立连接:注入时只是创建代理对象
- 首次调用时连接:第一次
send()时才建立TCP连接 - 后续复用连接:建立后的连接会被复用
如果需要立即建立连接,可以在生命周期钩子中手动调用:
import { OnApplicationBootstrap } from '@nestjs/common';
@Controller()
export class AppController implements OnApplicationBootstrap {
constructor(
@Inject('MATH_SERVICE') private readonly client: ClientProxy,
) {}
async onApplicationBootstrap() {
await this.client.connect();
}
}
typescript
关键概念总结
| 概念 | 说明 |
|---|---|
Transport.TCP | TCP传输层,NestJS默认的微服务通信方式 |
@MessagePattern | 定义请求-响应模式的消息处理器 |
ClientProxy.send() | 发送消息并等待响应(返回Observable) |
ClientsModule.register() | 在模块中注册微服务客户端 |
name(注入令牌) | 用于依赖注入的唯一标识 |
| 懒加载连接 | ClientProxy在首次调用时才建立连接 |
NestJS微服务支持的传输层
| 传输层 | Transport枚举 | 特点 |
|---|---|---|
| TCP | Transport.TCP | 默认方式,简单直接 |
| Redis | Transport.REDIS | 发布/订阅模式 |
| NATS | Transport.NATS | 高性能消息队列 |
| RabbitMQ | Transport.RMQ | 企业级消息队列 |
| Kafka | Transport.KAFKA | 大数据场景 |
| gRPC | Transport.GRPC | 高性能RPC框架 |
↑